package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
	"time"
)

// handlerFunc
func indexHandler(ctx *gin.Context) {
	fmt.Println("index...")
	name, ok := ctx.Get("name") //从上下文中取值（跨中间件取值）~~~~~~~~~~~~~~~~~~
	if !ok {
		name = "匿名用户"
	}
	ctx.JSON(http.StatusOK, gin.H{
		"msg": name,
	})
}

// 定义一个中间件m1：统计请求处理函数的耗时
func m1(ctx *gin.Context) {
	fmt.Println("m1 in...")
	//计时
	start := time.Now()
	ctx.Next() //调用后续的处理函数
	//ctx.Abort() //阻止调用后续的处理函数
	cost := time.Since(start) //从开始到现在花费的时间
	fmt.Printf("cost:%v\n", cost)
	fmt.Println("m1 out...")
}

func m2(ctx *gin.Context) {
	fmt.Println("m2 in...")
	ctx.Next() //调用后续的处理函数
	fmt.Println("m2 out...")
}

func m3(ctx *gin.Context) {
	fmt.Println("m3 in...")
	//ctx.Abort() //阻止调用后续的处理函数（即阻止调用indexHandler函数）
	ctx.Set("name", "xyy") //在上下文c中设置值~~~~~~~~~~~~~~~~~~

	//在中间件中启动新的 goroutine 时，只能使用 *gin.Context 变量的 只读副本（ctx.Copy()）
	/*
		go funcXX(ctx.Copy()) //在 funcXX 中只能使用 ctx 的拷贝
	*/
	fmt.Println("m3 out...")
}

func authMiddleware(doCheck bool) gin.HandlerFunc {
	//连接数据库
	//或者一些其他准备工作
	return func(ctx *gin.Context) {
		if doCheck {
			//存放具体的逻辑
			//是否登录的判断
			//if 是登录用户
			ctx.Next()
			// else
			// ctx.Abort()
		} else {
			ctx.Next()
		}
	}
}

func main() {
	r := gin.Default() //默认使用了 Logger() 和 Recovery() 中间件
	//Logger 中间件将 日志 写入 gin.DefaultWriter
	//Recovery 中间件会 recover 任何 panic

	// GET(relativePath string, handlers ...HandlerFunc) IRoutes
	r.GET("/index", m1, m2, m3, indexHandler)
	/*结果：
	m1 in...
	m2 in...
	index...
	m2 out...
	cost:0s
	m1 out...
	*/
	r.Use(m1, m2, m3, authMiddleware(true)) //全局注册中间件函数m1,下面的处理函数都会执行m1
	r.GET("/shop", func(context *gin.Context) {
		fmt.Println("shop~~~~~~~")
		context.JSON(http.StatusOK, gin.H{
			"msg": "shop",
		})
	})
	r.GET("/user", func(context *gin.Context) {
		context.JSON(http.StatusOK, gin.H{
			"msg": "user",
		})
	})

	//路由组注册中间件方法1：
	xxGroup := r.Group("/xx", authMiddleware(true))
	{
		xxGroup.GET("/index", func(context *gin.Context) {
			context.JSON(http.StatusOK, gin.H{"msg": "xxGroup"})
		})
	}

	/*//路由组注册中间件方法1：
	xx2Group := r.Group("/xx2")
	xx2Group.Use(authMiddleware(true))
	{
		xxGroup.GET("/index", func(context *gin.Context) {
			context.JSON(http.StatusOK, gin.H{"msg": "xx2Group"})
		})
	}*/

	r.Run(":8080")
}
